#include <malloc.h>
#include <ctime>
#include <list>
#include "file_io.h"

class FileIO;

using namespace std;

#define DEFAULT_TAG "<DEFAULT>"
#define DEFAULT_FILEPATH L"log.txt"
#define MAX_LOG_SIZE 500

// TODO: add mutex
// This class is constructed using singleton pattern. Currently it works
// correct only for single-thread applications
class Logger {
 public:
  // Structure to represent logs. Used instead of simple strings to allow
  // sorting by time, priority or tag
  struct LogEntry {
    char* time;
    char* message;
    char* tag;
    int priority;
  };

  // Get an instance of logger.
  static Logger* getInstance();

  ~Logger();

  // Log message with verbose (1) level and specified tag
  void verbose(char* message, char* tag = DEFAULT_TAG);

  // Log message with info (2) level and specified tag
  void info(char* message, char* tag = DEFAULT_TAG);

  // Log message with debug (3) level and specified tag
  void debug(char* message, char* tag = DEFAULT_TAG);

  // Log message with warn (4) level and specified tag
  void warn(char* message, char* tag = DEFAULT_TAG);

  // Log message with error (5) level and specified tag
  void error(char* message, char* tag = DEFAULT_TAG);
  
  // What a terrible failure! See http://developer.android.com/reference/android/util/Log.html#wtf(java.lang.String, java.lang.Throwable)
  // Log message with assert (6) level and specified tag
  void wtf(char* message, char* tag = DEFAULT_TAG);

  // Get logs with specified tag filter or minimal priority
  // If no filter is specified, returns all log entries
  LogEntry* getLogs(int minimal_priority = kVerbose, char* tag_filter = NULL);

  // Output logs to file
  void outputLogs(LogEntry* log_entries, wchar_t* filepath = DEFAULT_FILEPATH);

 private:
  LogEntry* _log_entries;

  int _logs;

  // Priority constants
  static const int kVerbose = 1;
  static const int kInfo = 2;
  static const int kDebug = 3;
  static const int kWarn = 4;
  static const int kError = 5;
  static const int kAssert = 6;

  // Matching singleton pattern
  Logger(Logger const&);              
  void operator=(Logger const&);

  // Constructor is private to match singleton pattern
  Logger();

  // Creates new log entry
  void log(char* message, char* tag, const int priority);

  // Returns specific displayed text for each priority value, f.e. [VERB] for verbose level
  char* getPriorityText(const int priority);

  // Returns current date and time in 'yyyy.mm.dd hh:mm:ss' format
  char* getCurrentTime();

  // Returns data from log entry in string format
  char* getLogString(LogEntry log_entry);

  // Returns data from a list of log entries in string format
  char** getLogStrings(LogEntry* log_entry, int* size);
};